package com.dib.neo.bkfs.server;

import com.dib.neo.bkfs.fs.BKFile;
import com.dib.neo.bkfs.fs.BKPath;
import com.dib.neo.bkfs.fs.FileInfo;
import com.google.common.collect.Lists;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.channels.FileLock;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.nio.file.spi.FileSystemProvider;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.bookkeeper.client.BKException;
import org.apache.bookkeeper.client.BookKeeper;
import org.apache.bookkeeper.client.LedgerHandle;
import org.apache.bookkeeper.client.LedgerEntry;
import org.apache.commons.configuration.FileSystem;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Enumeration;

public class TestClient {

  public static void main(String[] args)
      throws IOException, BKException, InterruptedException {
    //testBookKeeper();
    testBKFSClient();
    //testH2();

    return;
  }

  private static void testH2(){
    try {
      String db="bkfs://localhost:2181/h2/mdb2";
      String url = "jdbc:h2:"+db+";AUTO_SERVER=true";
      Connection connection = DriverManager.getConnection(url,"sa","hhrhl2016");
      PreparedStatement ps = null;

      ps = connection.prepareStatement("create table users\n"
          + "(\n"
          + "id int primary key not null,\n"
          + "name varchar(20) null,\n"
          + ")");
      ps.execute();//*/
      ps = connection.prepareStatement("insert into users (id,name) values (2,'guest')");
      ps.execute();
      ps = connection.prepareStatement("select * from users");
      ResultSet rs = ps.executeQuery();
      while(rs.next()){
        int id = rs.getInt("id");
        String name=rs.getString("name");
        System.out.println("id = " + id);
        System.out.println("name = " + name);
      }
      connection.commit();
      connection.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }

  private static void testBKFSClient()
      throws IOException {
    String name = "umds.mds3.log";//"node-v6.9.1-linux-x64.tar.xz";
    String path = "/d1/test/" + name;//ideaIU-2018.3-no-jdk.tar.gz";
    URI uri = URI.create("bkfs://localhost:2181"+path);
    BKPath bkpath = (BKPath)Paths.get(uri);
    /*
    final BKFile p = bkpath.open(StandardOpenOption.CREATE,StandardOpenOption.READ,StandardOpenOption.WRITE);

    if(!p.exists()){
      p.createNewFile();
    }

    System.out.println("p = " + p);//*/



    int count = 10;
    long start = System.currentTimeMillis();
    File file = new File("/" + name);



    for (int i = 0; i < count; i++) {
      long s1 = System.currentTimeMillis();

      try (FileInputStream in = new FileInputStream(file)) {
        byte[] buffer = new byte[ 1024 * 1024];
        int len = 0;
        long offset = 0;
        OutputStream out = bkpath.newOutputStream(false);
        while ((len = in.read(buffer)) != -1) {
          out.write(buffer,0,len);
//          ByteBuffer src = ByteBuffer.allocate(len);
//          src.put(buffer,0,len);
//          p.write(src,offset);
          offset += len;
        }
      }
      long t1 = System.currentTimeMillis() - s1;
      double speed1 = ((int) (1000000 * file.length() / (1024 * 1024 * t1))) / 1000.0;
      System.out.println("index=" + i + " t1=" + t1 + "ms speed1 = " + speed1 + "MB/s");
    }
    long end = System.currentTimeMillis();
    long time = (end - start) / count;
    double speed = ((int) (1000000 * file.length() / (1024 * 1024 * time))) / 1000.0;
    System.out.println("avg time=" + time + "ms speed = " + speed + "MB/s");
    //*/

    long start2 = System.currentTimeMillis();
    ExecutorService service  = Executors.newFixedThreadPool(1);
    List<Future<?>> jobs = Lists.newArrayList();
    for (int i = 0; i < count; i++) {
      final int index = i;
      Future<?> future = service.submit(() -> {
        long s1 = System.currentTimeMillis();

        try (FileOutputStream out = new FileOutputStream(
            Paths.get("/test/bak_" + index + "_" + name).toFile())) {
          try(InputStream in = bkpath.newInputStream()){
            byte[] buffer = new byte[ 1024 * 1024];

            while (in.available()>0) {
              int rlen = in.read(buffer);
              out.write(buffer, 0, rlen);
            }
          }

        }catch (Exception e){
          e.printStackTrace();
        }

        long t1 = System.currentTimeMillis() - s1+1;
        double speed1 = ((int) (1000000 * file.length() / (1024 * 1024 * t1))) / 1000.0;
        System.out.println("index=" + index + " t1=" + t1 + "ms speed1 = " + speed1 + "MB/s");
      });
      jobs.add(future);
    }
    for(Future<?> job : jobs){
      try {
        job.get();
      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (ExecutionException e) {
        e.printStackTrace();
      }
    }
    long end2 = System.currentTimeMillis();
    long time2 = (end2 - start2) / count;
    double speed2 = ((int) (1000000 * file.length() / (1024 * 1024 * time2))) / 1000.0;
    System.out.println("avg time2=" + time2 + "ms speed2 = " + speed2 + "MB/s");//*/
    System.out.println("bkpath.getFileInfo() = " + bkpath.getFileInfo());


  }

  private static void testBookKeeper() throws IOException, InterruptedException, BKException {
    BookKeeper bkc = new BookKeeper("node42:2181");
    // A password for the new ledger
    byte[] ledgerPassword = "alice&elsa".getBytes();
/*
    // Create a new ledger and fetch its identifier
    LedgerHandle lh = bkc.createLedger(BookKeeper.DigestType.MAC, ledgerPassword);
    long ledgerId = lh.getId();

    // Create a buffer for four-byte entries
    ByteBuffer entry = ByteBuffer.allocate(4);

    int numberOfEntries = 10;

    // Add entries to the ledger, then close it
    for (int i = 0; i < numberOfEntries; i++) {
      entry.putInt(i);
      entry.position(0);
      lh.addEntry(entry.array());
    }
    lh.close();
    System.out.println("ledgerId = " + ledgerId);
    //*/
    // Open the ledger for reading
    long ledgerId = 2;
    LedgerHandle lh = bkc.openLedger(ledgerId, BookKeeper.DigestType.MAC, ledgerPassword);

    // Read all available entries
    Enumeration<LedgerEntry> entries = lh.readEntries(0, lh.getLastAddConfirmed());

    while (entries.hasMoreElements()) {
      ByteBuffer result = ByteBuffer.wrap(entries.nextElement().getEntry());
      //Integer retrEntry = result.getInt();

      // Print the integer stored in each entry
      System.out.println(String.format("Result: %s", result.array().length));
    }

    // Close the ledger and the zk
    lh.close();
    bkc.close();
  }
}

